'use strict'

const Promise = require('bluebird')
const fs = require('fs')
const _ = require('lodash')
const request = Promise.promisify(require('request'))
const util = require('./util')
const prefix = 'https://api.weixin.qq.com/cgi-bin/'

const api = {
  accessToken: `${prefix}token?grant_type=client_credential`,
  temporary: {
    upload: `${prefix}media/upload?`,
    fetch: `${prefix}media/get?`
  },
  permanent: {
    upload: `${prefix}material/add_material?`,
    fetch: `${prefix}material/get_material?`,
    uploadNews: `${prefix}material/add_news?`,
    uploadNewsPic: `${prefix}media/uploadimg?`,
    del: `${prefix}material/del_material?`,
    update: `${prefix}material/update_news?`,
    count: `${prefix}material/get_materialcount?`,
    batch: `${prefix}material/batchget_material?`
  },
  // 用户标签管理
  user: {
    remark: `${prefix}user/info/updateremark?`,
    fetch: `${prefix}user/info?`,
    batchFetch: `${prefix}user/info/batchget?`,
  }
}

function Wechat(opts) {
  this.appID = opts.appID
  this.appSecret = opts.appSecret
  this.getAccessToken = opts.getAccessToken
  this.saveAccessToken = opts.saveAccessToken

  this.fetchAccessToken()
}

Wechat.prototype.isValidAccessToken =  function (data) { // 验证access_token正确性
  if (!data || !data.access_token || !data.expires_in) {
    return false
  }

  let access_token = data.access_token
  let expires_in = data.expires_in
  let now = new Date().getTime()

  if (now < expires_in) {
    return true
  } else {
    return false
  }
}

Wechat.prototype.updateAccessToken = function () { // 更新access_token
  let appID = this.appID
  let appSecret = this.appSecret
  let url = `${api.accessToken}&appid=${appID}&secret=${appSecret}`
  return new Promise(function (resolve, reject) {
     request({url: url,json: true}).then(res => {
      let data = res.body
      let now = new Date().getTime()
      let expires_in = now + (data.expires_in - 20) * 1000
      data.expires_in = expires_in
      resolve(data)
    })
  })

}

Wechat.prototype.reply = function () { // 回复内容
  let content = this.body
  let message = this.weixin
  let xml = util.tpl(content, message)

  this.status = 200
  this.type =  'application/xml'
  this.body = xml
}

Wechat.prototype.fetchAccessToken = function () { // 获取access_token
  let that = this
  if (this.access_token && this.expires_in) {
    if (this.isValidAccessToken(this)) {
      return Promise.resolve(this)
    }
  }

  return this.getAccessToken()
    .then(function (data) {
      try {
        data = JSON.parse(data)
      } catch (err) {
        return that.updateAccessToken()
      }

      if (that.isValidAccessToken(data)) {
        return Promise.resolve(data)
      } else {
        return that.updateAccessToken()
      }
    })
    .then(function (data) {
      that.access_token = data.access_token
      that.expires_in = data.expires_in

      that.saveAccessToken(JSON.stringify(data))
      return Promise.resolve(data)
    })
    .then(data => {
      return Promise.resolve()
    })
}

Wechat.prototype.uploadMaterial = function (type, material, permanent) { // 上传素材
  let that = this
  let form = {}
  let uploadUrl = api.temporary.upload

  if (permanent) {
    uploadUrl = api.permanent.upload
    _.extend(form, permanent)
  }

  if (type === 'pic') {
    uploadUrl = api.permanent.uploadNewsPic
  }

  if (type === 'news') {
    uploadUrl = api.permanent.uploadNews
    form = material
  } else {
    form.media = fs.createReadStream(material)
  }

  return new Promise(function (resolve, reject) {
    that
      .fetchAccessToken()
      .then(data => {
        let url = `${uploadUrl}&access_token=${data.access_token}`

        if (!permanent) {
          url += `&type=${type}`
        } else {
          form.access_token = data.access_token
        }

        let options = {
          method: 'POST',
          url: url,
          json: true
        }

        if (type === 'news') {
          options.body = form
        } else {
          options.formData = form
        }


        request(options).then(res => {
          let _data = res.body
          
          if (_data) {
            resolve(_data)
          } else {
            throw new Error('上传失败')
          }
        })
        .catch(err => {
          reject(err)
        })
      })
  })
}

Wechat.prototype.fetchMaterial = function (mediaId, type, permanent) { // 获取素材
  let that = this
  let fetchUrl = api.temporary.fetch
  if (permanent) {
    fetchUrl = api.permanent.fetch
  }

  return new Promise(function (resolve, reject) {
    that
      .fetchAccessToken()
      .then(data => {
        let url = `${fetchUrl}&access_token=${data.access_token}`
        let form = {}
        let option = {method: 'POST', url: url, json: true}
        if (permanent) {
          form.media_id = mediaId
          form.access_token = data.access_token
          option.body = form
        } else {
          if (type === 'video') {
            url = url.replace('https://', 'http://')
          }
          url += `&media_id=${mediaId}`
        }

        if (type === 'news' || type === 'video') {
          // console.log(option)
          request(option).then(res => {
            let _data = res.body
            if (_data) {
              resolve(_data)
            } else {
              throw new Error('获取失败')
            }
          }).catch(err => {
            reject(err)
          })
        } else {
          resolve(url)
        }
      })
  })
}

Wechat.prototype.deleteMaterial = function (mediaId) { // 删除永久素材
  let that = this
  let form = {
    media_id: mediaId
  }

  return new Promise(function (resolve, reject) {
    that
      .fetchAccessToken()
      .then(data => {
        let url = `${api.permanent.del}&access_token=${data.access_token}&media_id=${mediaId}`

        request({method: 'POST', url: url, body: form, json: true}).then((res) => {
          let _data = res[1]
          if (_data) {
            resolve(_data)
          } else {
            throw new Error('删除失败')
          }
        })
      })
  })
}

Wechat.prototype.updateMaterial = function (mediaId, news) { // 修改永久素材
  let that = this
  let form = {
    media_id: mediaId
  }

  _.extend(form, news)
  return new Promise(function (resolve, reject) {
    that
      .fetchAccessToken()
      .then(data => {
        let url = `${api.permanent.update}&access_token=${data.access_token}&media_id=${mediaId}`

        request({method: 'POST', url: url, body: form, json: true}).then((res) => {
          let _data = res[1]
          if (_data) {
            resolve(_data)
          } else {
            throw new Error('修改失败')
          }
        })
      })
  })
}

Wechat.prototype.countMaterial = function () { // 获取永久素材总数
  let that = this

  return new Promise(function (resolve, reject) {
    that
      .fetchAccessToken()
      .then(data => {
        let url = `${api.permanent.count}&access_token=${data.access_token}`
        request({method: 'POST', url: url, json: true}).then(res => {
          let _data = res.body
          if (_data) {
            resolve(_data)
          } else {
            throw new Error('获取素材数量失败')
          }
        })
      })
  })
}

Wechat.prototype.batchMaterial = function (options) { // 获取素材列表
  let that = this

  options.type = options.type || 'image'
  options.offset = options.offset || 0
  options.count = options.count || 1

  return new Promise(function (resolve, reject) {
    that
      .fetchAccessToken()
      .then(data => {
        let url = `${api.permanent.batch}&access_token=${data.access_token}`
        request({method: 'POST', url: url, body: options, json: true}).then(res => {
          let _data = res.body
          if (_data) {
            resolve(_data)
          } else {
            throw new Error('获取素材失败')
          }
        })
      })
  })
}

Wechat.prototype.remarkUser = function (openId, remark) { // 设置用户备注名
  let that = this
  return new Promise(function (resolve, reject) {
    that
      .fetchAccessToken()
      .then(function(data) {
        let url = `${api.user.remark}access_token=${data.access_token}`
        let form = {
          openid: openId,
          remark: remark
        }
        request({method: 'POST', url: url, body: form, json: true}).then(res => {
          let _data = res.body
          if (_data) {
            resolve(_data)
          } else {
            throw new Error('设置用户备注名失败')
          }
        }).catch(err => {
          reject(err)
        })
      })
  })
}

Wechat.prototype.batchFetchUsers = function (openIds, lang) { // 批量获取用户基本信息
  let that = this
  lang = lang || 'zh_CN'
  return new Promise(function (resolve, reject) {
    that
      .fetchAccessToken()
      .then(function(data) {
        let options = {
          url: url,
          json: true
        }
        if (_.isArray(openIds)) {
          options.url = `${api.user.batchFetch}access_token=${data.access_token}`
          options.form = {
            user_list: openIds
          }
          options.method = 'POST'
        } else {
          options.url = `${api.user.fetch}access_token=${data.access_token}&openid=${openIds}&lang=${lang}`
          options.method = 'get'
        }
        request(options).then(res => {
          let _data = res.body
          if (_data) {
            resolve(_data)
          } else {
            throw new Error('批量获取用户基本信息失败')
          }
        }).catch(err => {
          reject(err)
        })
      })
  })
}


module.exports = Wechat